/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
mxCodecRegistry.register(function () {
    /**
     * Class: mxEditorCodec
     *
     * Codec for <mxEditor>s. This class is created and registered
     * dynamically at load time and used implicitly via <mxCodec>
     * and the <mxCodecRegistry>.
     *
     * Transient Fields:
     *
     * - modified
     * - lastSnapshot
     * - ignoredChanges
     * - undoManager
     * - graphContainer
     * - toolbarContainer
     */
    var codec = new mxObjectCodec(new mxEditor(),
        ['modified', 'lastSnapshot', 'ignoredChanges',
            'undoManager', 'graphContainer', 'toolbarContainer']);

    /**
     * Function: beforeDecode
     *
     * Decodes the ui-part of the configuration node by reading
     * a sequence of the following child nodes and attributes
     * and passes the control to the default decoding mechanism:
     *
     * Child Nodes:
     *
     * stylesheet - Adds a CSS stylesheet to the document.
     * resource - Adds the basename of a resource bundle.
     * add - Creates or configures a known UI element.
     *
     * These elements may appear in any order given that the
     * graph UI element is added before the toolbar element
     * (see Known Keys).
     *
     * Attributes:
     *
     * as - Key for the UI element (see below).
     * element - ID for the element in the document.
     * style - CSS style to be used for the element or window.
     * x - X coordinate for the new window.
     * y - Y coordinate for the new window.
     * width - Width for the new window.
     * height - Optional height for the new window.
     * name - Name of the stylesheet (absolute/relative URL).
     * basename - Basename of the resource bundle (see <mxResources>).
     *
     * The x, y, width and height attributes are used to create a new
     * <mxWindow> if the element attribute is not specified in an add
     * node. The name and basename are only used in the stylesheet and
     * resource nodes, respectively.
     *
     * Known Keys:
     *
     * graph - Main graph element (see <mxEditor.setGraphContainer>).
     * title - Title element (see <mxEditor.setTitleContainer>).
     * toolbar - Toolbar element (see <mxEditor.setToolbarContainer>).
     * status - Status bar element (see <mxEditor.setStatusContainer>).
     *
     * Example:
     *
     * (code)
     * <ui>
     *   <stylesheet name="css/process.css"/>
     *   <resource basename="resources/app"/>
     *   <add as="graph" element="graph"
     *     style="left:70px;right:20px;top:20px;bottom:40px"/>
     *   <add as="status" element="status"/>
     *   <add as="toolbar" x="10" y="20" width="54"/>
     * </ui>
     * (end)
     */
    codec.afterDecode = function (dec, node, obj) {
        // Assigns the specified templates for edges
        var defaultEdge = node.getAttribute('defaultEdge');

        if (defaultEdge != null) {
            node.removeAttribute('defaultEdge');
            obj.defaultEdge = obj.templates[defaultEdge];
        }

        // Assigns the specified templates for groups
        var defaultGroup = node.getAttribute('defaultGroup');

        if (defaultGroup != null) {
            node.removeAttribute('defaultGroup');
            obj.defaultGroup = obj.templates[defaultGroup];
        }

        return obj;
    };

    /**
     * Function: decodeChild
     *
     * Overrides decode child to handle special child nodes.
     */
    codec.decodeChild = function (dec, child, obj) {
        if (child.nodeName == 'Array') {
            var role = child.getAttribute('as');

            if (role == 'templates') {
                this.decodeTemplates(dec, child, obj);
                return;
            }
        }
        else if (child.nodeName == 'ui') {
            this.decodeUi(dec, child, obj);
            return;
        }

        mxObjectCodec.prototype.decodeChild.apply(this, arguments);
    };

    /**
     * Function: decodeUi
     *
     * Decodes the ui elements from the given node.
     */
    codec.decodeUi = function (dec, node, editor) {
        var tmp = node.firstChild;
        while (tmp != null) {
            if (tmp.nodeName == 'add') {
                var as = tmp.getAttribute('as');
                var elt = tmp.getAttribute('element');
                var style = tmp.getAttribute('style');
                var element = null;

                if (elt != null) {
                    element = document.getElementById(elt);

                    if (element != null && style != null) {
                        element.style.cssText += ';' + style;
                    }
                }
                else {
                    var x = parseInt(tmp.getAttribute('x'));
                    var y = parseInt(tmp.getAttribute('y'));
                    var width = tmp.getAttribute('width');
                    var height = tmp.getAttribute('height');

                    // Creates a new window around the element
                    element = document.createElement('div');
                    element.style.cssText = style;

                    var wnd = new mxWindow(mxResources.get(as) || as,
                        element, x, y, width, height, false, true);
                    wnd.setVisible(true);
                }

                // TODO: Make more generic
                if (as == 'graph') {
                    editor.setGraphContainer(element);
                }
                else if (as == 'toolbar') {
                    editor.setToolbarContainer(element);
                }
                else if (as == 'title') {
                    editor.setTitleContainer(element);
                }
                else if (as == 'status') {
                    editor.setStatusContainer(element);
                }
                else if (as == 'map') {
                    editor.setMapContainer(element);
                }
            }
            else if (tmp.nodeName == 'resource') {
                mxResources.add(tmp.getAttribute('basename'));
            }
            else if (tmp.nodeName == 'stylesheet') {
                mxClient.link('stylesheet', tmp.getAttribute('name'));
            }

            tmp = tmp.nextSibling;
        }
    };

    /**
     * Function: decodeTemplates
     *
     * Decodes the cells from the given node as templates.
     */
    codec.decodeTemplates = function (dec, node, editor) {
        if (editor.templates == null) {
            editor.templates = [];
        }

        var children = mxUtils.getChildNodes(node);
        for (var j = 0; j < children.length; j++) {
            var name = children[j].getAttribute('as');
            var child = children[j].firstChild;

            while (child != null && child.nodeType != 1) {
                child = child.nextSibling;
            }

            if (child != null) {
                // LATER: Only single cells means you need
                // to group multiple cells within another
                // cell. This should be changed to support
                // arrays of cells, or the wrapper must
                // be automatically handled in this class.
                editor.templates[name] = dec.decodeCell(child);
            }
        }
    };

    // Returns the codec into the registry
    return codec;
}());